package db

import (
	"database/sql"
	"errors"
	"info/util"
	"reflect"
)

var namingStrategy = util.GetNamingStrategy(util.NamingStrategySnake)

func getEntityFields(entity interface{}, fields []interface{}, colTypes []*sql.ColumnType) error {
	if len(fields) != len(colTypes) {
		return errors.New("len(fields) must be equals to len(colTypes)")
	}
	// 反射获得对象信息
	v := reflect.ValueOf(entity)
	if v.Kind() != reflect.Ptr {
		return errors.New("argument must be a pointer")
	}
	e := v.Elem()
	if e.Kind() != reflect.Struct {
		return errors.New("argument is not a valid struct pointer")
	}

	// 组合可扫描slice
	for i, ct := range colTypes {
		cn := ct.Name()
		fn := namingStrategy.ColumnToField(cn)
		f := e.FieldByName(fn)
		if f.CanSet() && f.CanInterface() {
			fields[i] = f.Addr().Interface()
		} else {
			return errors.New("[" + fn + "] of [" + e.Type().Name() + "] is not assignable")
		}
	}

	return nil
}

func mapToEntities(entity []interface{}, rows sql.Rows) error {
	// 反射获得对象信息
	v := reflect.ValueOf(entity)
	if v.Kind() != reflect.Ptr {
		return errors.New("argument must be a pointer")
	}
	e := v.Elem()
	if e.Kind() != reflect.Struct {
		return errors.New("argument is not a valid struct pointer")
	}

	// 获取数据列信息
	colTypes, _ := rows.ColumnTypes()
	fields := make([]interface{}, len(colTypes))

	// 组合可扫描slice
	for i, ct := range colTypes {
		cn := ct.Name()
		fn := namingStrategy.ColumnToField(cn)
		f := e.FieldByName(fn)
		if f.CanSet() && f.CanInterface() {
			fields[i] = f.Addr().Interface()
		} else {
			return errors.New("[" + fn + "] of [" + e.Type().Name() + "] is not assignable")
		}
	}

	er := rows.Scan(fields...)
	if er != nil {
		return er
	}

	return nil
}
